/*
 * LibMediaDecoder.h
 *
 *  Created on: 2018年7月23日
 *      Author: terry
 */

#ifndef LIBMEDIADECODER_H_
#define LIBMEDIADECODER_H_

///////////////////////////////////////////////////////////////////
#ifdef WIN32

    #ifndef NOMINMAX
    #define NOMINMAX
    #endif //NOMINMAX

    //#pragma warning( disable : 4786 )
    #include <winsock2.h>
    //#include <windows.h>

#else


#endif //WIN32


///////////////////////////////////////////////////////////////////
#include <stddef.h>
#include <string.h>
///////////////////////////////////////////////////////////////////

#ifndef SOCKET_T
    #ifdef WIN32
        typedef SOCKET  socket_t;
    #else
        typedef int     socket_t;
    #endif // WIN32

    #define SOCKET_T

#endif //SOCKET_T



#ifdef _MSC_VER
#if (_MSC_VER >= 1700)
    #include <stdint.h>
#else
    typedef signed char     int8_t;
    typedef unsigned char   uint8_t;
    typedef short           int16_t;
    typedef unsigned short  uint16_t;
    typedef int             int32_t;
    typedef unsigned        uint32_t;
    typedef long long       int64_t;
    typedef unsigned long long   uint64_t;
#endif

#else
    #include <stdint.h>
#endif //_MSC_VER


///////////////////////////////////////////////////////////////////
#ifdef WIN32
    #ifndef DLLEXPORT
    #define DLLEXPORT __declspec(dllexport)
    #endif //DLLEXPORT
#else
    #ifndef DLLEXPORT
    #define DLLEXPORT __attribute__ ((visibility ("default")))
    #endif //DLLEXPORT
#endif //WIN32

///////////////////////////////////////////////////////////////////

#ifdef WIN32
#else
    typedef void*   HANDLE;
    typedef int     BOOL;
    typedef void*	HWND;
    typedef void*	HDC;

	#define WINAPI

#endif //


/////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C"
{
#endif

/////////////////////////////////////////////////////////////////////////////


typedef enum MDecode_MediaType
{
	MDECODE_MEDIA_NONE  = -1,
	MDECODE_MEDIA_VIDEO = 0,	/// 视频流
	MDECODE_MEDIA_AUDIO,		/// 音频流
	MDECODE_MEDIA_DATA,		/// 混合流
	MDECODE_MEDIA_SUBTITLE
} MDecode_MediaType;


typedef enum MDecode_CodecType
{
    MDECODE_CODEC_NONE = 0,

	MDECODE_CODEC_MPEG2= 2,
	MDECODE_CODEC_MPEG4= 13,

    MDECODE_CODEC_H264 = 28,
    MDECODE_CODEC_HEVC = 174,
	MDECODE_CODEC_H265 = MDECODE_CODEC_HEVC,

    MDECODE_CODEC_G711U = 65542,
    MDECODE_CODEC_G711A,

	MDECODE_CODEC_MP3 = 0x15001,
    MDECODE_CODEC_AAC = 0X15002,

	MDECODE_CODEC_RAW = 0X10101010
} MDecode_CodecType;


typedef enum MDecode_EventType
{
	MDECODE_EVENT_OPENING = 0X0100,	/// 打开文件中
	MDECODE_EVENT_OPEN_FAILED,		/// 打开失败
	MDECODE_EVENT_OPENED,			/// 打开成功
	MDECODE_EVENT_CLOSED,			/// 文件关闭

	MDECODE_EVENT_END,		/// 播放结束

	MDECODE_EVENT_FORMAT_READY,	/// 已知媒体格式

	MDECODE_EVENT_SEEKING,	/// 拖拽中
	MDECODE_EVENT_SEEKED,		/// 拖拽完成

	MDECODE_EVENT_FULLSCREEN,	/// 全屏变化
	MDECODE_EVENT_VOLUME,		/// 音量变化
	MDECODE_EVENT_MUTE,		/// 静音变化
	MDECODE_EVENT_SCALE,		/// 播放速度变化

	MDECODE_EVENT_PLAYING,		/// 播放中
	MDECODE_EVENT_PAUSED,			/// 暂停
	MDECODE_EVENT_STOPPED		/// 停止播放

} MDecode_EventType;


/**
 * 媒体格式
 */
typedef struct MDecode_Format
{
	int	codec;		/// 视频编码(或者混合编码)

	int audioCodec;	/// 音频编码
	int	channels;	/// 通道数
	int samplerate;	/// 采样率

	uint8_t* prop;
	int propSize;

} MDecode_Format;


typedef enum MDecode_MediaFlag
{
	MDECODE_FLAG_KEY = 0x01		/// 关键帧标识

} MDecode_MediaFlag;


/// pixel format
typedef enum MDecode_PixelFormat
{
	MDECODE_PIXEL_NONE = -1,
    
	MDECODE_PIXEL_I420  = 0,  /* yuv 4:2:0 planar YUV420P */
	MDECODE_PIXEL_RGB24 = 2,    /// RGB24
	MDECODE_PIXEL_BGR24,	/// BGR24

	MDECODE_PIXEL_NV12 = 25,  /* yuv 4:2:0, with one y plane and one packed u+v */

	MDECODE_PIXEL_RGBA = 28,
	MDECODE_PIXEL_BGRA = 30,

} MDecode_PixelFormat;


/**
 * 音频采样格式
 */
typedef enum MDecode_SampleFormat {
    MDECODE_SAMPLE_NONE = -1,//!< MDECODE_SAMPLE_NONE
    MDECODE_SAMPLE_U8,          ///< unsigned 8 bits
    MDECODE_SAMPLE_S16,         ///< signed 16 bits
    MDECODE_SAMPLE_S32,         ///< signed 32 bits
    MDECODE_SAMPLE_FLT,         ///< float
    MDECODE_SAMPLE_DBL,         ///< double

    MDECODE_SAMPLE_U8P,         ///< unsigned 8 bits, planar
    MDECODE_SAMPLE_S16P,        ///< signed 16 bits, planar
    MDECODE_SAMPLE_S32P,        ///< signed 32 bits, planar
    MDECODE_SAMPLE_FLTP,        ///< float, planar
    MDECODE_SAMPLE_DBLP,        ///< double, planar

    MDECODE_SAMPLE_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
} MDecode_SampleFormat;


typedef enum MDecode_Const
{
	MDECODE_MAX_PLANE = 8	/// 最大平面数
} MDecode_Const;

/// 音视频帧
typedef struct MDecode_Frame
{
	int type;	///@see MFrameType, 用于区分音频/视频
	int fmt;	/// 帧格式, @see MPixelFormat. 对于音频, @see MSampleFormat

	unsigned char* data[MDECODE_MAX_PLANE];	/// 媒体数据, 对于视频, 每个元素指向一个平面;对于音频, 元素指向通道
	int linesize[MDECODE_MAX_PLANE];		/// 第几个平面|通道的字节数

	int64_t pts;	/// 时间戳
	int flags;		/// 标记

	/// for video only
	int width;		/// 视频高
	int height;		/// 视频宽

	/// for audio only
	int channels;	/// 音频通道
	int sampleRate;	/// 采样率
	int samples;	/// 采样数

} MDecode_Frame;

/////////////////////////////////////////////////////////////////////////////

/**
 * 初始化解码库
 * @return TRUE 如果成功
 */
DLLEXPORT BOOL WINAPI MDecode_Init();

/**
 * 清理解码库
 */
DLLEXPORT void WINAPI MDecode_Uninit();

/**
 * 获取版本
 * @return 版本
 */
DLLEXPORT const char* WINAPI MDecode_GetVersion();


/**
 * 获取操作的错误码
 * @param handle 解码器句柄，NULL 表示全局错误码
 * @return 0 表示没有错误
 */
DLLEXPORT int WINAPI MDecode_GetLastError(HANDLE handle);


/**
 * 获取解码器句柄
 * @return 解码器句柄， NULL表示失败， 需要调用MDecode_DestroyPlayer进行关闭
 */
DLLEXPORT HANDLE WINAPI MDecode_CreateHandle();

/**
 * 销毁解码器句柄
 * @param handle 解码器句柄
 */
DLLEXPORT void WINAPI MDecode_DestroyHandle(HANDLE handle);


/**
 * 打开流式解码器
 * @param handle 解码器句柄
 * @param buffer 缓冲区指针
 * @param length 缓冲区长度
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_OpenStream(HANDLE handle, MDecode_Format* fmt);


/**
 * 关闭流式解码器
 * @param handle 解码器句柄
 */
DLLEXPORT void WINAPI MDecode_CloseStream(HANDLE handle);


/**
 * 输入视频数据
 * @param handle 解码器句柄
 * @param buffer 数据缓冲区
 * @param length 数据长度
 * @param mediaType 数据类型，比如视频，音频，复合流
 * @param flags  关键帧标识等, @see MDecode_MediaFlag
 * @return TRUE 表示解码成功
 */
DLLEXPORT BOOL WINAPI MDecode_InputData(HANDLE handle, int mediaType, const uint8_t* buffer, int length, int64_t pts, int flags);


/**
 * 重置输入缓冲区
 * @param handle
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_ResetBuffer(HANDLE handle);


/**
 * 设置显示窗口
 * @param handle 解码器句柄
 * @param hwnd  窗口句柄
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_SetVideoWnd(HANDLE handle, HWND hwnd);



/**
 * 获取视频分辨率，调用MDecode_InputData解码成功之后才会返回有效值
 * @param pWidth 宽
 * @param pHeight 高
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_GetPictureSize(HANDLE handle, int* pWidth, int* pHeight);

/**
 * 抓图，格式为BMP
 * @param handle 解码器句柄
 * @param filename 文件名
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_Snap(HANDLE handle, const char* filename);

/**
 * 刷新窗口
 * @param handle 解码器句柄
 */
DLLEXPORT void WINAPI MDecode_Refresh(HANDLE handle);

/**
 * 播放
 * @param handle
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_Play(HANDLE handle);

/**
 * 暂停
 * @param handle
 * @param pauseIt TRUE 表示暂停，FALSE表示恢复
 * @param TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_Pause(HANDLE handle, BOOL pauseIt);

/**
 * 停止
 * @param handle 解码器句柄
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_Stop(HANDLE handle);


/**
 * 解码回调
 * @param handle 解码器句柄
 * @param pPicture 图像对象指针
 * @param pUser 设置回调时传入的环境指针
 */
typedef void (* MediaDecodeCallback)(HANDLE handle, MDecode_Frame* frame, void* pUser);

/**
 * 显示回调
 * @param handle 解码器句柄
 * @param hdc 绘图设备环境句柄
 * @param pUser 设置回调时环境指针
 *
 */
typedef void (* MediaDrawCallback)(HANDLE handle, HDC hdc, HWND hwnd, void* pUser);

/**
 * 设置解码回调
 * @param handle 解码句柄
 * @param cb 回调函数
 * @param pUser 环境指针
 * @return TRUE 表示成功
 *
 */
DLLEXPORT BOOL WINAPI MDecode_SetDecodeCallback(HANDLE handle, MDecode_PixelFormat pixelFormat, MediaDecodeCallback cb, void* pUser);

/**
 * 设置显示回调，可在回调中进行绘图操作
 * @param handle 解码器句柄
 * @param cb 回调函数
 * @param pUser 环境指针
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_SetDrawCallback(HANDLE handle, MediaDrawCallback cb, void* pUser);




/**
 * 打开文件
 * @param filename 文件名
 * @return 解码器句柄， 需要调用MDecode_CloseFile关闭
 */
DLLEXPORT BOOL WINAPI MDecode_OpenFile(HANDLE handle, const char* filename);


/**
 * 关闭文件解码器
 * @param handle 解码器句柄
 */
DLLEXPORT void WINAPI MDecode_CloseFile(HANDLE handle);


/**
 * 打开文件
 * @param url 文件名或者网络URL
 * @param params 参数, 可以为NULL或者空
 * @return 解码器句柄， 需要调用 MDecode_CloseFile 关闭
 */
DLLEXPORT BOOL WINAPI MDecode_OpenFileEx(HANDLE handle, const char* url, const char* params);



/**
 * 获取播放进度
 * @param handle
 * @return 播放进度，范围为[0, 1]
 */
DLLEXPORT double WINAPI MDecode_GetPos(HANDLE handle);

/**
 * 设置播放文件，即定位操作seek
 * @param handle 解码器句柄
 * @param pos 进度值，范围为[0, 1]
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_SetPos(HANDLE handle, double pos);

/**
 * 获取文件的总时长,
 * @param handle 解码器句柄
 * @param pSeconds 总时长，单位为秒，有些文件无法获取时长
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_GetDuration(HANDLE handle, double* pSeconds);


/**
 * 设置播放速度
 * @param handle 解码器句柄
 * @param scale 播放速度，范围为[1/8, 8], 1表示正常速度，8 表示快八倍速，1/8表示慢八倍速
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_SetScale(HANDLE handle, double scale);


/**
 * 获取播放速度
 * @param handle
 * @param pScale
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_GetScale(HANDLE handle, double* pScale);


/**
 * 设置文件播放结束通知消息，消息的wparam表示句柄，lparam 事件类型
 * @param handle 解码器句柄
 * @param hwnd 消息窗口句柄
 * @param msg 消息类型
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_SetFileEndMsg(HANDLE handle, HWND hwnd, uint32_t msg);



/**
 * 打开音频解码
 * @param handle
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL  WINAPI MDecode_OpenSound(HANDLE    handle);

/**
 * 关闭音频解码
 * @param handle 解码器句柄
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL  WINAPI MDecode_CloseSound(HANDLE   handle);

/**
 * 设置音频音量
 * @param handle 解码器句柄
 * @param volume 音量，范围为：[0-100], 0 表示静音
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL  WINAPI MDecode_SetVolume(HANDLE    handle, int  volume);


/**
 * 获取音量
 * @param handle
 * @param pVolume 音量
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL  WINAPI MDecode_GetVolume(HANDLE    handle, int*  pVolume);




/**
 * 创建录像
 * @param filename 文件名
 * @return 录像句柄， NULL表示失败
 */
DLLEXPORT HANDLE WINAPI MDecode_OpenRecord(const char* filename);


/**
 * 写入媒体流
 * @param handle 录像句柄
 * @param buffer 数据指针
 * @param length    数据长度
 * @param mediaType  数据类型
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_WriteRecordData(HANDLE handle, int mediaType,
        const uint8_t* buffer, int length, int64_t pts, int flags);


/**
 * 关闭录像
 * @param handle 录像句柄
 *
 */
DLLEXPORT void WINAPI MDecode_CloseRecord(HANDLE handle);



/**
 * 获取当前播放的时间
 * @handle 解码库句柄
 * @pts  时间，单位为毫秒
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_GetTime(HANDLE handle, int64_t* pts);

/**
 * 定位到指定时间点
 * @param handle	解码库句柄
 * @param pts	时间, 单位为毫秒
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL WINAPI MDecode_Seek(HANDLE handle, int64_t pts);


/**
 * 设置显示比例
 * 如果cx,cy= 0, 保持视频的原始比率
 * @param player
 * @param cx	宽度比例
 * @param cy	高度比例
 * @return
 */
DLLEXPORT BOOL WINAPI MDecode_SetRatio(HANDLE handle, int cx, int cy);


/**
 * 事件回调句柄
 * @param player	播放器句柄
 * @param event		事件类型
 * @param value		事件附加值
 * @param size		附加值长度
 * @param pUser	回调环境
 */
typedef void (*DecoderEventCallback)(HANDLE handle, int event, const char* value, int size, void* pUser);


/**
 * 设置事件回调句柄
 * @param player	播放器
 * @param cb		回调函数
 * @param pUser		回调环境
 * @return
 */
DLLEXPORT BOOL MDecode_SetEventCallback(HANDLE handle, DecoderEventCallback cb, void* pUser);

/**
 * 设置视频过滤器
 * @param filterString	过滤器字符串, ffmpeg规则
 * @return TRUE 表示成功
 */
DLLEXPORT BOOL MDecode_SetVideoFilter(HANDLE handle, const char* filterString);

/////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
}
#endif

#endif /* LIBMEDIADECODER_H_ */
